{
 "cells": [
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {
    "collapsed": true
   },
   "outputs": [],
   "source": [
    "\"\"\"Summary of tensorflow basics.\n",
    "\n",
    "Parag K. Mital, Jan 2016.\"\"\""
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {
    "collapsed": true
   },
   "outputs": [],
   "source": [
    "# %% Import tensorflow and pyplot\n",
    "import tensorflow as tf\n",
    "import matplotlib.pyplot as plt"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {
    "collapsed": true
   },
   "outputs": [],
   "source": [
    "# %% tf.Graph represents a collection of tf.Operations\n",
    "# You can create operations by writing out equations.\n",
    "# By default, there is a graph: tf.get_default_graph()\n",
    "# and any new operations are added to this graph.\n",
    "# The result of a tf.Operation is a tf.Tensor, which holds\n",
    "# the values."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {
    "collapsed": true
   },
   "outputs": [],
   "source": [
    "# %% First a tf.Tensor\n",
    "n_values = 32\n",
    "x = tf.linspace(-3.0, 3.0, n_values)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {
    "collapsed": true
   },
   "outputs": [],
   "source": [
    "# %% Construct a tf.Session to execute the graph.\n",
    "sess = tf.Session()\n",
    "result = sess.run(x)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {
    "collapsed": true
   },
   "outputs": [],
   "source": [
    "# %% Alternatively pass a session to the eval fn:\n",
    "x.eval(session=sess)\n",
    "# x.eval() does not work, as it requires a session!"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {
    "collapsed": true
   },
   "outputs": [],
   "source": [
    "# %% We can setup an interactive session if we don't\n",
    "# want to keep passing the session around:\n",
    "sess.close()\n",
    "sess = tf.InteractiveSession()"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {
    "collapsed": true
   },
   "outputs": [],
   "source": [
    "# %% Now this will work!\n",
    "x.eval()"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {
    "collapsed": true
   },
   "outputs": [],
   "source": [
    "# %% Now a tf.Operation\n",
    "# We'll use our values from [-3, 3] to create a Gaussian Distribution\n",
    "sigma = 1.0\n",
    "mean = 0.0\n",
    "z = (tf.exp(tf.neg(tf.pow(x - mean, 2.0) /\n",
    "                   (2.0 * tf.pow(sigma, 2.0)))) *\n",
    "     (1.0 / (sigma * tf.sqrt(2.0 * 3.1415))))"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {
    "collapsed": true
   },
   "outputs": [],
   "source": [
    "# %% By default, new operations are added to the default Graph\n",
    "assert z.graph is tf.get_default_graph()"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {
    "collapsed": true
   },
   "outputs": [],
   "source": [
    "# %% Execute the graph and plot the result\n",
    "plt.plot(z.eval())"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {
    "collapsed": true
   },
   "outputs": [],
   "source": [
    "# %% We can find out the shape of a tensor like so:\n",
    "print(z.get_shape())"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {
    "collapsed": true
   },
   "outputs": [],
   "source": [
    "# %% Or in a more friendly format\n",
    "print(z.get_shape().as_list())"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {
    "collapsed": true
   },
   "outputs": [],
   "source": [
    "# %% Sometimes we may not know the shape of a tensor\n",
    "# until it is computed in the graph.  In that case\n",
    "# we should use the tf.shape fn, which will return a\n",
    "# Tensor which can be eval'ed, rather than a discrete\n",
    "# value of tf.Dimension\n",
    "print(tf.shape(z).eval())"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {
    "collapsed": true
   },
   "outputs": [],
   "source": [
    "# %% We can combine tensors like so:\n",
    "print(tf.pack([tf.shape(z), tf.shape(z), [3], [4]]).eval())"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {
    "collapsed": true
   },
   "outputs": [],
   "source": [
    "# %% Let's multiply the two to get a 2d gaussian\n",
    "z_2d = tf.matmul(tf.reshape(z, [n_values, 1]), tf.reshape(z, [1, n_values]))"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {
    "collapsed": true
   },
   "outputs": [],
   "source": [
    "# %% Execute the graph and store the value that `out` represents in `result`.\n",
    "plt.imshow(z_2d.eval())"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {
    "collapsed": true
   },
   "outputs": [],
   "source": [
    "# %% For fun let's create a gabor patch:\n",
    "x = tf.reshape(tf.sin(tf.linspace(-3.0, 3.0, n_values)), [n_values, 1])\n",
    "y = tf.reshape(tf.ones_like(x), [1, n_values])\n",
    "z = tf.mul(tf.matmul(x, y), z_2d)\n",
    "plt.imshow(z.eval())"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {
    "collapsed": true
   },
   "outputs": [],
   "source": [
    "# %% We can also list all the operations of a graph:\n",
    "ops = tf.get_default_graph().get_operations()\n",
    "print([op.name for op in ops])"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {
    "collapsed": true
   },
   "outputs": [],
   "source": [
    "# %% Lets try creating a generic function for computing the same thing:\n",
    "def gabor(n_values=32, sigma=1.0, mean=0.0):\n",
    "    x = tf.linspace(-3.0, 3.0, n_values)\n",
    "    z = (tf.exp(tf.neg(tf.pow(x - mean, 2.0) /\n",
    "                       (2.0 * tf.pow(sigma, 2.0)))) *\n",
    "         (1.0 / (sigma * tf.sqrt(2.0 * 3.1415))))\n",
    "    gauss_kernel = tf.matmul(\n",
    "        tf.reshape(z, [n_values, 1]), tf.reshape(z, [1, n_values]))\n",
    "    x = tf.reshape(tf.sin(tf.linspace(-3.0, 3.0, n_values)), [n_values, 1])\n",
    "    y = tf.reshape(tf.ones_like(x), [1, n_values])\n",
    "    gabor_kernel = tf.mul(tf.matmul(x, y), gauss_kernel)\n",
    "    return gabor_kernel"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {
    "collapsed": true
   },
   "outputs": [],
   "source": [
    "# %% Confirm this does something:\n",
    "plt.imshow(gabor().eval())"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {
    "collapsed": true
   },
   "outputs": [],
   "source": [
    "# %% And another function which can convolve\n",
    "def convolve(img, W):\n",
    "    # The W matrix is only 2D\n",
    "    # But conv2d will need a tensor which is 4d:\n",
    "    # height x width x n_input x n_output\n",
    "    if len(W.get_shape()) == 2:\n",
    "        dims = W.get_shape().as_list() + [1, 1]\n",
    "        W = tf.reshape(W, dims)\n",
    "\n",
    "    if len(img.get_shape()) == 2:\n",
    "        # num x height x width x channels\n",
    "        dims = [1] + img.get_shape().as_list() + [1]\n",
    "        img = tf.reshape(img, dims)\n",
    "    elif len(img.get_shape()) == 3:\n",
    "        dims = [1] + img.get_shape().as_list()\n",
    "        img = tf.reshape(img, dims)\n",
    "        # if the image is 3 channels, then our convolution\n",
    "        # kernel needs to be repeated for each input channel\n",
    "        W = tf.concat(2, [W, W, W])\n",
    "\n",
    "    # Stride is how many values to skip for the dimensions of\n",
    "    # num, height, width, channels\n",
    "    convolved = tf.nn.conv2d(img, W,\n",
    "                             strides=[1, 1, 1, 1], padding='SAME')\n",
    "    return convolved"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {
    "collapsed": true
   },
   "outputs": [],
   "source": [
    "# %% Load up an image:\n",
    "from skimage import data\n",
    "img = data.astronaut()\n",
    "plt.imshow(img)\n",
    "print(img.shape)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {
    "collapsed": true
   },
   "outputs": [],
   "source": [
    "# %% Now create a placeholder for our graph which can store any input:\n",
    "x = tf.placeholder(tf.float32, shape=img.shape)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {
    "collapsed": true
   },
   "outputs": [],
   "source": [
    "# %% And a graph which can convolve our image with a gabor\n",
    "out = convolve(x, gabor())"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {
    "collapsed": true
   },
   "outputs": [],
   "source": [
    "# %% Now send the image into the graph and compute the result\n",
    "result = tf.squeeze(out).eval(feed_dict={x: img})\n",
    "plt.imshow(result)"
   ]
  }
 ],
 "metadata": {
  "kernelspec": {
   "display_name": "Python [Root]",
   "language": "python",
   "name": "Python [Root]"
  },
  "language_info": {
   "codemirror_mode": {
    "name": "ipython",
    "version": 2
   },
   "file_extension": ".py",
   "mimetype": "text/x-python",
   "name": "python",
   "nbconvert_exporter": "python",
   "pygments_lexer": "ipython2",
   "version": "2.7.11"
  }
 },
 "nbformat": 4,
 "nbformat_minor": 0
}
